/*
 * SamplePlugin.Echo
 * Andy Tidball
 * 
 * Project: Black Lightning Sample Plugin
 * Copyright: GNU General Public License
 */

using System;
using System.Text;
using System.Text.RegularExpressions;
using BlackLightning.PluginLib;
using BlackLightning.PluginLib.Modules;
using BlackLightning.PluginLib.Modules.Packets;

// this attribute is actually tagging the assembly (the entire plugin DLL), not the module class itself
// I just find it convenient to put in this file because it refers to the module that is defined here
// this attribute tells Black Lightning that this assembly contains a module whose type is EchoModule
// this is how Black Lightning knows which types it can load from this assembly
// an attribute like this (passing the appropriate type) is necessary for each module in the plugin
// note that since this attribute isn't inside a namespace{} block, the namespace must be included in the type
[assembly: BLModule(typeof(SamplePlugin.EchoModule))]

namespace SamplePlugin {
	/// <summary>
	/// A sample module which implements a simple @echo command.
	/// </summary>
	[ModuleName("Echo")] // this attribute names the module "Echo" from Black Lightning's standpoint, otherwise it would be called "EchoModule" which isn't very user-friendly
	public class EchoModule : IModule {
		// constants
		private const string HelpText  = @"This module implements the @echo command.";
		private const string EchoUsage = @"@echo [string]
  string: The string to echo to the front end.";

		/// <summary>
		/// We can fire this event to send a private message to Black Lightning.
		/// </summary>
		public event SendMessageEventHandler SendMessage;

		/// <summary>
		/// We can fire this event to send a packet to Black Lightning for routing to other modules and possibly another program.
		/// </summary>
		public event SendPacketEventHandler SendPacket;

		/// <summary>
		/// Gets a property of the module.
		/// </summary>
		/// <param name="Property">The property of the module that Black Lightning is requesting.</param>
		/// <returns>The value of the requested property, or null if this module doesn't use that property.</returns>
		public object GetProperty(ModuleProperty Property) {
			switch (Property) {
				case ModuleProperty.HelpText: return HelpText;
				default:                      return null;
			}
		}

		/// <summary>
		/// Called by Black Lightning whenever it has a private message for us.
		/// </summary>
		/// <param name="Message">The private message that Black Lightning is sending to us.</param>
		public void HandleMessage(Message Message) {
			// you don't have to break this up into a separate function for each type of message
			// but I find the code to be a lot more readable when I do
			if (Message is LoadedMessage) {
				// this message is sent to us when we are first loaded
				HandleMessage_Loaded(Message as LoadedMessage);
			} else if (Message is UnloadedMessage) {
				// this message is sent to us when we're about to be unloaded
				HandleMessage_Unloaded(Message as UnloadedMessage);
			}
		}

		/// <summary>
		/// Handles all LoadedMessages sent to us.
		/// </summary>
		/// <param name="Message">The LoadedMessage sent to us by Black Lightning.</param>
		private void HandleMessage_Loaded(LoadedMessage Message) {
			// our first and only job when being loaded is to register to recieve any packets containing our @echo command

			// first we need to create a filter which will be used by Black Lightning to filter all incoming packets
			// any packet which matches our filter will be sent to us for processing
			// this filter will only match command packets received from the Front End and bound for Black Lightning
			// in addition it will only match packets whose command is "@echo"
			CommandPacketFilter EchoFilter = new CommandPacketFilter(Program.FrontEnd, Program.BlackLightning, "@echo");

			// next, we need to construct a RegisterPacketMessage to send to Black Lightning to register the filter
			RegisterPacketMessage EchoMessage = new RegisterPacketMessage(EchoFilter);

			// finally, we just need to send the message by raising our SendMessage event
			// we pass ourselves as the sender of the message
			// and we construct a SendMessageEventArgs to send the message along in
			SendMessage(this, new SendMessageEventArgs(EchoMessage));

			// note that I spread that out over a number of lines for clarity
			// if you wanted to, you could condense all of that to one line
			// which is easier to read if you have a lot of other code here, and saves having to create a bunch of named variables
			// for example:
			// SendMessage(this, new SendMessageEventArgs(new RegisterPacketMessage(new CommandPacketFilter(Program.FrontEnd, Program.BlackLightning, "@echo"))));
			// newlines could be added to improve readability as well
		}

		/// <summary>
		/// Handles all UnloadedMessages sent to us.
		/// </summary>
		/// <param name="Message">The UnloadedMessage sent to us by Black Lightning.</param>
		private void HandleMessage_Unloaded(UnloadedMessage Message) {
			// we don't actually really have to do anything special when we're unloaded
			// but if we needed to clean anything up when we're finished, this is where we would do it
		}

		/// <summary>
		/// Called by Black Lightning whenever it has a packet for us to process.
		/// </summary>
		/// <param name="Packet">The packet that we should handle.</param>
		public void HandlePacket(ref BLPacket Packet) {
			// Black Lightning only calls this if the given packet matches one of our registered filters
			// since we only registered one filter, we know that this is an @echo command

			// since we registered a CommandPacketFilter, we know that this packet is in fact a CommandPacket
			// we know this because only packets with type CommandPacket can match filters of type CommandPacketFilter
			CommandPacket P = Packet as CommandPacket;

			// we need to echo the arguments back to the user
			// if there are no arguments send the usage instead
			if (P.Arguments.Length == 0) {
				// (see below for more information about sending packets)
				SendPacket(this, new SendPacketEventArgs(new RawBLPacket(Program.BlackLightning, Program.FrontEnd, EchoUsage)));
				return;
			}

			// join the arguments together with spaces
			string Output = string.Join(" ", P.Arguments);

			// okay, now we just need to send the output to the front end
			// we do this by sending out a packet of our own, by raising our SendPacket event

			// first, construct the packet to send
			// our packet is coming from Black Lightning and going to the Front End
			// it contains the output string that we just created
			RawBLPacket OutputPacket = new RawBLPacket(Program.BlackLightning, Program.FrontEnd, Output);

			// next, send the packet inside of a SendPacketEventArgs
			// and pass ourselves as the sender
			// Black Lightning will now route the packet to the front end for us
			// note that it will also send the packet to any other interested modules!
			SendPacket(this, new SendPacketEventArgs(OutputPacket));

			// note that, like registering packets, this could easily be combined into a single line
			// see above where we send the echo command's usage if they don't supply any arguments

			// finally, we should suppress this packet
			// since we handled it and know that no other modules are meant to deal with it
			// this will tell Black Lightning to not send the packet to any more modules OR to its destination
			P.Suppress();
		}
	}
}
